/**       
 * @{#} PooledObject.java Create on 2012-3-29 下午2:11:03       
 *       
 * Copyright (c) 2012 by able.       
 */
package __javable.core.util.pool.impl;

/**
 * 
 * 
 * @history <PRE>
 * --------------------------------------------------------- 
 * VERSION       DATE            BY       CHANGE/COMMENT 
 * --------------------------------------------------------- 
 * 1.0           2012-3-29      able         create 
 * ---------------------------------------------------------
 * </PRE>
 * 
 */
public class PooledObject<T> implements Comparable<PooledObject<T>> {

	private final T object;
	private volatile PooledObjectState state = PooledObjectState.IDLE;
	private final long createTime = System.currentTimeMillis();
	private volatile long lastBorrowTime = createTime;
	private volatile long lastReturnTime = createTime;

	public PooledObject(T object) {
		this.object = object;
	}

	public T getObject() {
		return object;
	}

	public long getCreateTime() {
		return createTime;
	}

	public long getActiveTimeMillis() {
		long rTime = lastReturnTime;
		long bTime = lastBorrowTime;

		if (rTime > bTime) {
			return rTime - bTime;
		} else {
			return System.currentTimeMillis() - bTime;
		}
	}

	public long getIdleTimeMillis() {
		return System.currentTimeMillis() - lastReturnTime;
	}

	public long getLastBorrowTime() {
		return lastBorrowTime;
	}

	public long getLastReturnTime() {
		return lastReturnTime;
	}

	@Override
	public int compareTo(PooledObject<T> other) {
		final long lastActiveDiff = this.getLastReturnTime() - other.getLastReturnTime();
		if (lastActiveDiff == 0) {
			// make sure the natural ordering is consistent with equals
			// see java.lang.Comparable Javadocs
			return System.identityHashCode(this) - System.identityHashCode(other);
		}
		// handle int overflow
		return (int) Math.min(Math.max(lastActiveDiff, Integer.MIN_VALUE), Integer.MAX_VALUE);
	}

	@Override
	public String toString() {
		StringBuilder result = new StringBuilder();
		result.append("Object: ");
		result.append(object.toString());
		result.append(", State: ");
		result.append(state.toString());
		return result.toString();
	}

	public synchronized boolean startEvictionTest() {
		if (state == PooledObjectState.IDLE) {
			state = PooledObjectState.MAINTAIN_EVICTION;
			return true;
		}

		return false;
	}

	public synchronized boolean endEvictionTest(LinkedBlockingDeque<PooledObject<T>> idleQueue) {
		if (state == PooledObjectState.MAINTAIN_EVICTION) {
			state = PooledObjectState.IDLE;
			return true;
		} else if (state == PooledObjectState.MAINTAIN_EVICTION_RETURN_TO_HEAD) {
			state = PooledObjectState.IDLE;
			if (!idleQueue.offerFirst(this)) {
				// TODO - Should never happen
			}
		}

		return false;
	}

	public synchronized boolean allocate() {
		if (state == PooledObjectState.IDLE) {
			state = PooledObjectState.ALLOCATED;
			lastBorrowTime = System.currentTimeMillis();
			return true;
		} else if (state == PooledObjectState.MAINTAIN_EVICTION) {
			// TODO Allocate anyway and ignore eviction test
			state = PooledObjectState.MAINTAIN_EVICTION_RETURN_TO_HEAD;
			return false;
		}
		// TODO if validating and testOnBorrow == true then pre-allocate for
		// performance
		return false;
	}

	public synchronized boolean deallocate() {
		if (state == PooledObjectState.ALLOCATED) {
			state = PooledObjectState.IDLE;
			lastReturnTime = System.currentTimeMillis();
			return true;
		}

		return false;
	}

	public synchronized void invalidate() {
		state = PooledObjectState.INVALID;
	}
}
